package b649a01.poperators;

import java.nio.ByteBuffer;
import java.util.Hashtable;
import java.util.StringTokenizer;

import b649a01.runners.sim_p;

/***
 * Floating point load calculator.
 * 
 * @author Chao Sun
 * @version 1.0
 */
public class f_load extends calculator {
	private double t;
	private double s;
	private String register;
	private int offset;

	/**
	 * Constructor.
	 */
	public f_load(sim_p sim, int i, int j, String op) {
		super(sim, i, j, op);
		Hashtable<String, Integer> cycleHash = simulator.getcycleHash();
		this.cycleNum = cycleHash.get(op);
		busyComUnit = "ADD.D";
	}

	/**
	 * Set locks to registers. Set computing unit lock.
	 * 
	 * @param opTokenizer
	 *          the string tokenizer containing all the operands
	 */
	@Override
	public void fetchRegs(StringTokenizer opTokenizer) {
		// add computing unit lock
		comUnitProperty.put("unit", busyComUnit);
		comUnitProperty.put("pipeIndex", pipelineIndex);
		simulator.addbusyComUnits(this, comUnitProperty);
		// get register name and index
		target = opTokenizer.nextToken();
		tIndex = Integer.parseInt(target.substring(1));
		// update write register, both local and in main processor
		writeRegs.add(target);
		writeRegProperty.put("vector", writeRegs);
		writeRegProperty.put("pipeIndex", pipelineIndex);
		simulator.addwriteRegs(this, writeRegProperty);
		// get read source
		source1 = opTokenizer.nextToken();
		StringTokenizer sTokenizer = new StringTokenizer(source1, "(");
		offset = Integer.parseInt(sTokenizer.nextToken());
		register = sTokenizer.nextToken();
		if (!register.startsWith("R")) {
			System.err.println("Address must be stored in an integer register");
			System.exit(1);
		}
		readRegs.add(register);
		readRegProperty.put("vector", readRegs);
		readRegProperty.put("pipeIndex", pipelineIndex);
		simulator.aadreadRegs(this, readRegProperty);
	}

	/**
	 * Assign values to register unless there is RAW hazard. Remove read locks.
	 */
	@Override
	public void assignRegs() {
		if (readMemOffs.isEmpty()) {
			int registerNum = Integer.parseInt(register.substring(1, register
					.length() - 1));
			R = simulator.getR();
			s1Index = R[registerNum] + offset;
			// update read memory offset, both local and in main processor
			readMemOffs.add(s1Index);
			readMemProperty.put("vector", readMemOffs);
			readMemProperty.put("pipeIndex", pipelineIndex);
			simulator.addreadMemOffs(this, readMemProperty);
			simulator.removereadRegs(readRegProperty);
			readRegs.clear();
		}
		byte dumpArray[] = simulator.getdumpArray();
		ByteBuffer buffer = ByteBuffer.allocate(8);
		buffer.put(dumpArray, s1Index, 8);
		s = buffer.getDouble(0);
		simulator.removereadMemOffs(readMemProperty);
		readMemOffs.clear();
	}

	/**
	 * Execute an arithmetic instruction. Remove computing unit lock.
	 */
	@Override
	public void execute() {
		if (!finishFlag) {
			t = s;
			finishFlag = true;
		}

		cycleNum--;
	}

	/**
	 * Write results into register. Remove write locks.
	 */
	@Override
	public void writeBack() {
		simulator.wbF(t, tIndex);
		simulator.removewriteRegs(writeRegProperty);
		writeRegs.clear();
		aliveFlag = false;
	}

}